package com.kapukapu.gateway.filter;

import java.nio.charset.StandardCharsets;
import java.util.List;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kapukapu.gateway.util.IpUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;

/**
 * @author: sivan
 * @date: 2019/12/22
 * @email: zifanuu@gmail.com
 */
@Slf4j
@AllArgsConstructor
public class TokenGlobalFilter implements GlobalFilter, Ordered {
	private ObjectMapper objectMapper;

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		List<String> token = exchange.getRequest().getHeaders().get("Token");

		return chain.filter(exchange).then(getOther(exchange, token));
	}

	private Mono<Void> getOther(ServerWebExchange exchange, List<String> token) {
		return Mono.fromRunnable(() -> {
			HttpStatus statusCode = exchange.getResponse().getStatusCode();
			if (log.isDebugEnabled()) {
				String localIPAddress = IpUtil.getLocalIPAddress();
				String remoteIPAddress = IpUtil.getRemoteIPAddress(exchange.getRequest());
				String uri = exchange.getRequest().getURI().getPath();
				log.debug(
						"Service IP: [{}]. User IP: [{}]. Request Path: '{}'. Token: '{}'",
						localIPAddress, remoteIPAddress, uri, token);
			}
			if (statusCode.is4xxClientError()) {
				unAuth(exchange.getResponse(), statusCode.getReasonPhrase());
			}
		});
	}

	private Mono<Void> unAuth(ServerHttpResponse resp, String msg) {
		resp.setStatusCode(HttpStatus.UNAUTHORIZED);
		resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
		String result = "";
		try {
			result = objectMapper.writeValueAsString(
					new ResponseEntity<>(msg, HttpStatus.UNAUTHORIZED));
		}
		catch (JsonProcessingException e) {
			log.error(e.getMessage(), e);
		}
		DataBuffer buffer = resp.bufferFactory()
				.wrap(result.getBytes(StandardCharsets.UTF_8));
		return resp.writeWith(Flux.just(buffer));
	}

	@Override
	public int getOrder() {
		return Integer.MIN_VALUE;
	}
}
